/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved.
 */

package com.example.util;

import com.example.constant.IsvProduceConstant;
import com.example.model.IMessageResp;
import com.example.model.IsvProduceReq;
import com.fasterxml.jackson.databind.ObjectMapper;

import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Map;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;

public class IsvProduceAPI {
    /**
     * 默认编码：UTF-8
     */
    private static final String CHARSET = "UTF-8";

    private static ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 验证签名
     *
     * @param isvProduceReq 请求参数
     * @param request
     * @param accessKey
     */
    public static IMessageResp verifySignature(IsvProduceReq isvProduceReq, HttpServletRequest request, String accessKey) throws Exception {
        IMessageResp resp = new IMessageResp();
        resp.setResultCode(ResultCodeEnum.SUCCESS.getResultCode());
        resp.setResultMsg(ResultCodeEnum.SUCCESS.getResultMsg());
        Map<String, String[]> paramsMap = request.getParameterMap();

        // 获取请求时间戳
        String reqTimestamp = getParamValue(paramsMap, IsvProduceConstant.TIMESTAMP);
        if (StringUtils.isEmpty(reqTimestamp)) {
            resp.setResultCode(ResultCodeEnum.INVALID_PARAM.getResultCode());
            resp.setResultMsg(ResultCodeEnum.INVALID_PARAM.getResultMsg());
            return resp;
        }

        // 请求时间戳建议与当前时间相差不超过60s
        if (!validateReqTime(reqTimestamp)) {
            resp.setResultCode(ResultCodeEnum.INVALID_PARAM.getResultCode());
            resp.setResultMsg(ResultCodeEnum.INVALID_PARAM.getResultMsg());
            return resp;
        }

        // 获取随机字符串
        String nonce = getParamValue(paramsMap, IsvProduceConstant.NONCE);
        if (StringUtils.isEmpty(nonce)) {
            resp.setResultCode(ResultCodeEnum.INVALID_PARAM.getResultCode());
            resp.setResultMsg(ResultCodeEnum.INVALID_PARAM.getResultMsg());
            return resp;
        }

        // 获取请求里的签名
        String reqSignature = getParamValue(paramsMap, IsvProduceConstant.SIGNATURE);
        if (StringUtils.isEmpty(reqSignature)) {
            resp.setResultCode(ResultCodeEnum.INVALID_TOKEN.getResultCode());
            resp.setResultMsg(ResultCodeEnum.INVALID_TOKEN.getResultMsg());
            return resp;
        }

        String reqParams = objectMapper.writeValueAsString(isvProduceReq);
        String signature = getSignature(accessKey, reqParams, nonce ,reqTimestamp);

        // 判断计算后的签名与云市场请求中传递的签名是否一致 不区分大小写
        if (reqSignature.equalsIgnoreCase(signature)) {
            return resp;
        }
        resp.setResultCode(ResultCodeEnum.INVALID_TOKEN.getResultCode());
        resp.setResultMsg(ResultCodeEnum.INVALID_TOKEN.getResultMsg());
        return resp;
    }

    /**
     * 根据入参生成对应的签名信息
     *
     * @param accessKey
     * @param reqParams 请求参数
     * @param nonce 随机数
     * @param reqTimestamp 时间戳
     * @return 签名结果
     */
    private static String getSignature(String accessKey, String reqParams, String nonce, String reqTimestamp) {
        // 加密请求体
        String encryptBody = generateSignature(accessKey, reqParams);

        // 生成签名
        return generateSignature(accessKey, accessKey + nonce + reqTimestamp + encryptBody);
    }

    private static String getParamValue(Map<String, String[]> paramsMap, String param) {
        String[] paramArray = paramsMap.get(param);
        if (null == paramArray || paramArray.length == 0) {
            return null;
        }
        return paramArray[0];
    }

    private static boolean validateReqTime(String reqTimestamp) {
        long reqUTCTime = Long.parseLong(reqTimestamp);
        return System.currentTimeMillis() - reqUTCTime <= 60000L;
    }

    public static byte[] hmacSHA256(String macKey, String macData) {
        try {
            SecretKeySpec secret = new SecretKeySpec(macKey.getBytes(CHARSET), "HmacSHA256");
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(secret);
            return mac.doFinal(macData.getBytes(CHARSET));
        } catch (UnsupportedEncodingException | InvalidKeyException | NoSuchAlgorithmException e) {
            return new byte[0];
        }
    }

    /**
     * 获取请求体签名
     *
     * @param key  accessKey
     * @param body 待签名的body体字符串
     * @return 生成的签名
     */
    public static String generateSignature(String key, String body) {
        return Hex.encodeHexString(hmacSHA256(key, body));
    }

}

